package com.proj.android.canyondefense.core.impl;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import com.proj.android.canyondefense.core.base.IAudio;
import com.proj.android.canyondefense.core.base.IFileIO;
import com.proj.android.canyondefense.core.base.IGame;
import com.proj.android.canyondefense.core.base.IGraphics;
import com.proj.android.canyondefense.core.base.IInput;
import com.proj.android.canyondefense.core.base.Screen;

import android.app.Activity;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.opengl.GLSurfaceView.Renderer;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.view.Window;
import android.view.WindowManager;
 
public class GLGame extends Activity implements IGame, Renderer{
	enum GLGameState {
        Initialized,
        Running,
        Paused,
        Finished,
        Idle
    }
	
	private GLSurfaceView _glView;    
    private GLGraphics _glGraphics;
    private IAudio _audio;
    private IInput _input;
    private IFileIO _fileIO;
    private Screen _screen;
    private GLGameState _state = GLGameState.Initialized;
    private Object _stateChanged = new Object();
    private long _startTime = System.nanoTime();
    private WakeLock _wakeLock;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    	super.onCreate(savedInstanceState);
    	requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                             WindowManager.LayoutParams.FLAG_FULLSCREEN);
        _glView = new GLSurfaceView(this);
        _glView.setRenderer(this);
        setContentView(_glView);
        
        _glGraphics = new GLGraphics(_glView);
        _fileIO = new AndroidFileIO(getAssets());
        _audio = new AndroidAudio(this);
        _input = new AndroidInput(this, _glView, 1, 1);
        PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
        _wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, "GLGame");  
    }
    
    @Override
    protected void onResume() {
    	super.onResume();
    	_glView.onResume();
    	_wakeLock.acquire();
    }
    
    @Override
    protected void onPause() {
    	synchronized(_stateChanged) {
            if(isFinishing()) {            
                _state = GLGameState.Finished;
            } else {
            	_state = GLGameState.Paused;
            }
            while(true) {
                try {
                    _stateChanged.wait();
                    break;
                } catch(InterruptedException e) {         
                }
            }
        }
        _wakeLock.release();
        _glView.onPause();  
        super.onPause();
    }
    
	public void onDrawFrame(GL10 gl) {
		GLGameState state = null;
        
        synchronized(_stateChanged) {
            state = this._state;
        }
        
        if(state == GLGameState.Running) {
            float deltaTime = (System.nanoTime() - _startTime) / 1000000000.0f;
            _startTime = System.nanoTime();
            
            _screen.update(deltaTime);
            _screen.present(deltaTime);
        }
        
        if(state == GLGameState.Paused) {
            _screen.pause();            
            synchronized(_stateChanged) {
                this._state = GLGameState.Idle;
                _stateChanged.notifyAll();
            }
        }
        
        if(state == GLGameState.Finished) {
            _screen.pause();
            _screen.dispose();
            synchronized(_stateChanged) {
                this._state = GLGameState.Idle;
                _stateChanged.notifyAll();
            }            
        }
	}
	
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		
	}
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		_glGraphics.setGL(gl);
        
        synchronized(_stateChanged) {
            if(_state == GLGameState.Initialized)
                _screen = getStartScreen();
            _state = GLGameState.Running;
            _screen.resume();
            _startTime = System.nanoTime();
        }        
	}
	public IInput getInput() {
		return _input;
	}
	public IFileIO getFileIO() {
		return _fileIO;
	}
	public IAudio getAudio() {
		return _audio;
	}
	public IGraphics getGraphics() {
		throw new IllegalStateException("[GLGame] :: getGraphics - We are using OpenGL!");
	}
	
	public GLGraphics getGLGraphics() {
		return _glGraphics;
	}
	
	public void setScreen(Screen screen) {
		if (screen == null) {
            throw new IllegalArgumentException("Screen must not be null");
		}

        this._screen.pause();
        this._screen.dispose();
        screen.resume();
        screen.update(0);
        this._screen = screen;
	}
	public Screen getCurrentScreen() {
		return _screen;
	}
	
	public Screen getStartScreen() {
		// TODO Auto-generated method stub
		return null;
	}
}
